package matchthreegame.extensions;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import matchthreegame.dataBase.DBManagerHelper;
import matchthreegame.handlers.GetAmountOfMoneyRequestHandler;
import matchthreegame.handlers.GetListOfUsersForNameHandler;
import matchthreegame.handlers.GetRankingListsHandler;
import matchthreegame.handlers.GetStoreInfoRequestHandler;
import matchthreegame.handlers.InviteUserToBuddylistHandler;
import matchthreegame.handlers.JoinPlayerToWaitingList;
import matchthreegame.handlers.LoginEventHandler;
import matchthreegame.handlers.InviteBuddyToPlayGameHandler;
import matchthreegame.handlers.PingRequestHandler;
import matchthreegame.handlers.ReturnToLobbyRequestHandler;
import matchthreegame.handlers.UpdateMoneyRequestHandler;
import matchthreegame.handlers.UpgradeHeroRequestHandler;
import matchthreegame.schedulerTasks.AutoCreateGamesTask;
import matchthreegame.serverEvents.OnServerReadyHandler;
import matchthreegame.serverEvents.OnUserJoinZoneHandler;
import matchthreegame.serverEvents.OnUserLeaveGameRoomHandler;
import matchthreegame.utils.Bot;
import matchthreegame.utils.BotsManager;
import matchthreegame.utils.WaitingList;

import com.smartfoxserver.v2.api.CreateRoomSettings;
import com.smartfoxserver.v2.api.CreateRoomSettings.RoomExtensionSettings;
import com.smartfoxserver.v2.core.SFSEventType;
import com.smartfoxserver.v2.entities.Room;
import com.smartfoxserver.v2.entities.User;
import com.smartfoxserver.v2.entities.data.SFSArray;
import com.smartfoxserver.v2.entities.variables.RoomVariable;
import com.smartfoxserver.v2.entities.variables.SFSRoomVariable;
import com.smartfoxserver.v2.exceptions.SFSJoinRoomException;
import com.smartfoxserver.v2.extensions.SFSExtension;

public class MatchThreeGameZoneExtension extends SFSExtension {

	private ScheduledExecutorService scheduledExecutor;
	private ScheduledFuture<?> autoCreateGames = null;
	private WaitingList waitingPlayers;
	public Room lobby = null;
	private DBManagerHelper dbManager;

	public static final String DATABASE_ID = "dbID";

	public static final String CMD_JOIN_USER_TO_WAITING_LIST  = "JUWL";
	public static final String CMD_GET_LIST_OF_USERS_FOR_NAME = "GLUN";
	public static final String CMD_INVITE_BUDDY_TO_PLAY_GAME  = "IBPG";
	public static final String CMD_INVITE_USER_TO_BUDDYLIST   = "IUTB";
	public static final String CMD_GET_RANKING_LISTS          = "GRL";
	public static final String CMD_UPDATE_MONEY_FOR_USER	  = "UMFU";
	public static final String CMD_RETURN_TO_LOBBY	          = "RTL";
	public static final String CMD_PING_REQUEST	              = "PR";
	public static final String CMD_GET_AMOUNT_OF_MONEY	      = "GAOM";
	public static final String CMD_UPGRADE_HERO               = "UH";
	public static final String CMD_GET_STORE_INFO	          = "GSI";
	 
	// Invitation constants
	public final String INVITATION_TYPE       = "INVT";
	public final String INVITATION_TYPE_GAME  = "INVG";
	public final String INVITATION_TYPE_BUDDY = "INVB";
	public final String INVITEE_NAME          = "IVEN";

	public final String USERNAME              = "USRN";

	//Bot constants
	public static final String IS_PLAYING_WITH_BOT = "isPlayingWithBot";
	public static final String BOT_NAME            = "botName";
	public static final String BOT_WINS            = "botWins";
	public static final String BOT_LOSSES    	   = "botLosses";
	public static final String BOT_RANK      	   = "botRank";
	public static final String BOT_HERO_TYPE 	   = "botHeroType";
	public static final String BOT_HERO_PRODUCES   = "botHeroProduces";
	public static final String BOT_HERO_ATTACK     = "botHeroAttack";
	
	@Override
	public void init() {

		trace("MatchThreeGameZoneExtension Extension init.");

		addEventHandler(SFSEventType.USER_LOGIN, LoginEventHandler.class);
		addEventHandler(SFSEventType.USER_JOIN_ZONE , OnUserJoinZoneHandler.class);
		addEventHandler(SFSEventType.SERVER_READY , OnServerReadyHandler.class);
		addEventHandler(SFSEventType.USER_DISCONNECT , OnUserLeaveGameRoomHandler.class);

		addRequestHandler(CMD_INVITE_BUDDY_TO_PLAY_GAME, InviteBuddyToPlayGameHandler.class);
		addRequestHandler(CMD_INVITE_USER_TO_BUDDYLIST, InviteUserToBuddylistHandler.class);
		addRequestHandler(CMD_JOIN_USER_TO_WAITING_LIST, JoinPlayerToWaitingList.class);
		addRequestHandler(CMD_GET_LIST_OF_USERS_FOR_NAME, GetListOfUsersForNameHandler.class);
		addRequestHandler(CMD_GET_RANKING_LISTS, GetRankingListsHandler.class);
		addRequestHandler(CMD_UPDATE_MONEY_FOR_USER, UpdateMoneyRequestHandler.class);
		addRequestHandler(CMD_GET_AMOUNT_OF_MONEY, GetAmountOfMoneyRequestHandler.class);
		addRequestHandler(CMD_RETURN_TO_LOBBY, ReturnToLobbyRequestHandler.class);
		addRequestHandler(CMD_PING_REQUEST, PingRequestHandler.class);
		addRequestHandler(CMD_UPGRADE_HERO, UpgradeHeroRequestHandler.class);
		addRequestHandler(CMD_GET_STORE_INFO, GetStoreInfoRequestHandler.class);

		this.waitingPlayers = new WaitingList();
		this.lobby = this.getParentZone().getRoomByName("The Lobby");
		this.scheduledExecutor = Executors.newScheduledThreadPool(3);

		// UNCOMMENT to work properly !!!
		this.autoCreateGames = scheduledExecutor.scheduleAtFixedRate(
				new AutoCreateGamesTask(this), 5, 10, TimeUnit.SECONDS);

		//Create DBManager class
		dbManager = new DBManagerHelper(getParentZone().getDBManager(), this);
		
		BotsManager.getBotsManager().extension = new WeakReference<MatchThreeGameZoneExtension>(this);

	}

	//Start new game with given IDs of players
	public void startGame(final ArrayList<Integer> userIds) {

		//Remove this players from waiting list
		for (int userID : userIds) {
			this.waitingPlayers.remove(userID);
		}

		//Create new room and join users in it
		String roomName = new Random().nextInt(200) + "" + new Random().nextInt(200) + " roomName";

		CreateRoomSettings crs = new CreateRoomSettings();
		crs.setName(roomName);
		crs.setMaxUsers(4);
		crs.setMaxVariablesAllowed(10);
		crs.setMaxSpectators(0);
		crs.setPassword("");
		crs.setDynamic(true);
		crs.setGame(true);
		crs.setExtension(new RoomExtensionSettings("MatchThreeGameExtension", "matchthreegame.extensions.MatchThreeGameRoomExtension"));

		try {
			Room roomToJoin = getApi().createRoom(this.getParentZone(), crs, getApi().getUserById(userIds.get(0)));

			for (int userID : userIds) {
				User user = getApi().getUserById(userID);
				getApi().joinRoom(user, roomToJoin);
			}

			//Add player IDs to room variable
			ArrayList<RoomVariable> roomVariables = new ArrayList<RoomVariable>();
			SFSArray players = new SFSArray();
			players.addInt(getApi().getUserById(userIds.get(0)).getPlayerId());
			if ( userIds.size() == 1 ) {
				trace("Start game with bot !");
				initBot(roomVariables);
				roomVariables.add(new SFSRoomVariable(IS_PLAYING_WITH_BOT, true));
			} else {
				players.addInt(getApi().getUserById (userIds.get(1)).getPlayerId());
				roomVariables.add(new SFSRoomVariable(IS_PLAYING_WITH_BOT, false));
			}

			roomVariables.add(new SFSRoomVariable("players", players));
			getApi().setRoomVariables(null, roomToJoin, roomVariables);

		} catch (Exception e) {
			trace("Error when creating room and joining players in it !");
			e.printStackTrace();
		}

	}

	private void initBot(ArrayList<RoomVariable> roomVariables) {

		//Choose bot 
		Bot bot = BotsManager.getBotsManager().getBot();
		String botName = bot.getBotName();

		roomVariables.add(new SFSRoomVariable(BOT_NAME, botName));

	}

	//Add user that joined the zone to Lobby room
	public void joinUserToLobby(User userToAdd) {
		trace(userToAdd.getName() + " try to join to Lobby room!" );
		try {
			getApi().joinRoom(userToAdd, this.lobby);
			trace("User: " + userToAdd.getId() + " joined Lobby room!" );
		} catch (SFSJoinRoomException e) {
			trace("User: " + userToAdd.getId() + " could not join Lobby room !!!" );
			e.printStackTrace();
		}

	}

	//Add user that joined the zone to waiting list
	public void addUserToWaitingList(User userToAdd) {

		trace("User to add to waiting list: " + userToAdd.getId()  );
		waitingPlayers.addUser(userToAdd);

	}

	public WaitingList getWaitingList() {

		return waitingPlayers;

	}

	public DBManagerHelper getDBHelper() {

		return this.dbManager;

	}

	@Override
	public void destroy() 
	{

		super.destroy();
		trace("MatchThreeGameZoneExtension destroyed.");

	}

}
